#include "VSCuller.h"
#include "VSSpatial.h"
#include "VSGeometry.h"
#include "VSGraphicInclude.h"
using namespace VSEngine2;
VSRenderContext VSRenderContext::ms_RenderContextNULL;
VSCuller::VSCuller(unsigned int uiCullerType,int iUseMaterialIndex)
{
	m_uiPlaneNum = 0;
	m_uiPlaneState =0xffffffff;
	for (unsigned int j = 0 ; j < RG_MAX ; j++)
	{
		for (unsigned int i = 0 ; i < VST_MAX ; i++)
		{
			m_VisibleSet[j][i].Clear();
		}
	}
	
	m_LightSet.Clear();
	m_pCamera = NULL;
	m_iUseMaterialIndex = iUseMaterialIndex;
	m_uiCullerType = uiCullerType;
}
VSCuller::~VSCuller()
{

}
bool VSCuller::PushPlane(const VSPlane3 & Plane)
{
	if(m_uiPlaneNum > VS_MAX_PLANE_NUM)
		return false;
	m_Plane[m_uiPlaneNum] = Plane;
	m_uiPlaneNum++;
	return true;
}
bool VSCuller::PushCameraPlane(VSCamera &Camera)
{
	VSPlane3 Plane[VSCamera::CP_MAX];
	Camera.GetPlane(Plane);
	for(unsigned int i =0 ; i < VSCamera::CP_MAX; i++)
	{
		if(!PushPlane(Plane[i]))
			return 0;
	}
	m_pCamera = &Camera;
	return 1;
}
bool VSCuller::PopPlane(VSPlane3 &Plane)
{
	if(!m_uiPlaneNum)
		return false;
	Plane = m_Plane[m_uiPlaneNum];
	m_uiPlaneNum--;
	return true;
}
bool VSCuller::InsertObject(VSRenderContext &VisibleContext,unsigned int uiVisibleSetType,unsigned int uiRenderGroup)
{
	if(uiVisibleSetType >= VST_MAX || uiRenderGroup >= RG_MAX)
		return 0;
	m_VisibleSet[uiRenderGroup][uiVisibleSetType].AddElement(VisibleContext);
	return 1;
}
unsigned int VSCuller::IsVisible(const VSAABB3 &BV)
{
	if(!m_uiPlaneNum)
		return 0;
	int iP = m_uiPlaneNum - 1;
	unsigned int uiMask = 1 << iP;
	unsigned int uiPlaneInNum = 0;
	for (unsigned int i = 0; i < m_uiPlaneNum; i++, iP--, uiMask >>= 1)
	{
		if (m_uiPlaneState & uiMask)
		{
			int iSide = BV.RelationWith(m_Plane[iP]);

			if (iSide == VSFRONT)
			{
				
				return VSF_NONE;
			}

			if (iSide == VSBACK)
			{
				
				m_uiPlaneState &= ~uiMask;
				uiPlaneInNum++;
			}
		}
		else
		{
			uiPlaneInNum++;
		}
	}
	if (uiPlaneInNum == m_uiPlaneNum)
	{
		return VSF_ALL;
	}
	else
	{
		return VSF_PARTIAL;
	}
}
bool VSCuller::RenderPriority::operator()(VSRenderContext & p1,VSRenderContext & p2)
{
	unsigned int uiMaterialAddr1 = 0;
	unsigned int uiMaterialAddr2 = 0;
	unsigned int uiMeshDateAddr1 = 0;
	unsigned int uiMeshDateAddr2 = 0;

	uiMaterialAddr1 = (unsigned int)p1.m_pMaterialInstance->GetMaterial();
	uiMaterialAddr2 = (unsigned int)p2.m_pMaterialInstance->GetMaterial();



	if (p1.m_pSpatial->GetST() == VSSpatial::ST_GEOMETRY)
	{
		uiMeshDateAddr1 = (unsigned int)(((VSGeometry *)p1.m_pSpatial)->GetMeshDate());

	}
	if (p2.m_pSpatial->GetST() == VSSpatial::ST_GEOMETRY)
	{
		uiMeshDateAddr2 = (unsigned int)(((VSGeometry*)p2.m_pSpatial)->GetMeshDate());
	}

	if (uiMaterialAddr1 >uiMaterialAddr2)
	{
		return 1;
	}
	else if (uiMaterialAddr1 < uiMaterialAddr2)
	{
		return 0;
	}
	else
	{
		if (uiMeshDateAddr1 > uiMeshDateAddr2)
		{
			return 1;
		}
		else if (uiMeshDateAddr1 < uiMeshDateAddr2)
		{
			return 0;
		}
		else
		{
			return 1;
		}
	}

}
void VSCuller::Sort()
{
	VSCamera * pCamera = m_pCamera;
	for (unsigned int j = 0 ; j < RG_MAX ; j++)
	{
		if (m_VisibleSet[j][VST_BASE].GetNum() > 0)
		{
			m_VisibleSet[j][VST_BASE].Sort(0,m_VisibleSet[j][VST_BASE].GetNum() - 1,RenderPriority());

		}
		
		if (m_VisibleSet[j][VST_ALPHABLEND].GetNum() > 0 && pCamera)
		{
			m_VisibleSet[j][VST_ALPHABLEND].Sort(0,m_VisibleSet[j][VST_BASE].GetNum() - 1,AlphaPriority(pCamera));

		}

		if (m_VisibleSet[j][VST_ALPHATEST].GetNum() > 0)
		{
			m_VisibleSet[j][VST_ALPHATEST].Sort(0,m_VisibleSet[j][VST_ALPHATEST].GetNum() - 1,RenderPriority());
		}
	}
	
}
bool VSCuller::AlphaPriority::operator()(VSRenderContext & p1,VSRenderContext & p2)
{
	if (!m_pCamera)
	{
		return 1;
	}
	VSVector3 vLength1 = m_pCamera->GetWorldTranslate() - p1.m_pSpatial->GetWorldTranslate(); 
	VSVector3 vLength2 = m_pCamera->GetWorldTranslate() - p2.m_pSpatial->GetWorldTranslate(); 

	if (vLength1.GetSqrLength() > vLength2.GetSqrLength())
	{
		return 0;
	}
	return 1;

}
